package hxm.monads;



/**
 * The FutureMonad delays execution until its underlying Future object is completed.
 * 
 * @author Simon Krajewski
 */

class FutureMonad 
{
	static public function bind<A, B>(a:Future<A>, f:A -> Future<B>):Future<B>
	{
		var f = map(a, f);
		return f.expr;
	}
	
	static public function map<A, B>(a:Future<A>, f:A->B):Future<B>
	{
		var ret = new Future<B>(null);

		if (a.isComplete)
			ret.complete(f(a.expr));
		else
			startListener(a, ret, f);
		return ret;
	}
	
	static public function yield<A>(a:A):Future<A> return new Future(a, true)
	
	static public var zero = new Future();
	
	static function startListener<A, B>(inFuture:Future<A>, outFuture:Future<B>, f:A->B)
	{
		inFuture.addListener(function(expr) outFuture.complete(f(expr)));
	}
}

class Future<T>
{
	public var expr(default, null):T;
	public var isComplete(default, null):Bool;
	
	var listeners:Array < T->Void > ;
	public function new(?expr:T, isComplete = false)
	{
		this.expr = expr;
		this.isComplete = isComplete;
		listeners = [];
	}
	
	public function addListener(l:T->Void) listeners.push(l)
	
	public function complete(expr:T)
	{
		this.expr = expr;
		isComplete = true;
		
		for (l in listeners)
			l(this.expr);
	}
}